from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.db.models import F, CharField, OuterRef, Prefetch, Subquery, IntegerField
from django.db.models.functions import Substr
from django.db.models.query import Cast
from lib.rest_api.perms import HasDjangoPermission
from rest_framework import generics
from rest_framework.views import APIView, Response

from ..models import AuditManagement, AMTag
from . import serializers
from project import models as p_models
from media.models import File

class BaseAPIListView(generics.ListAPIView):
    model = None
    serializer_class = None

    def get_base_queryset(self):
        # cache the _content_type
        if not hasattr(self, '_content_type'):
            self._content_type = ContentType.objects.get_for_model(self.model)
        return (
            serializers.default_queryset
            .filter(content_type=self._content_type)
            .select_related('auditor')
        )
    
    # note, don't use a variable, since `ContentType` requires django_content_type
    # database table, and it will crash when you do database migration
    def get_queryset(self):
        return self.get_base_queryset().prefetch_related('content_object')


class ProjectBaseAPIListView(BaseAPIListView):
    def get_permissions(self):
        return [HasDjangoPermission(["user.can_manage_projects"])]
    
class ProjectSubBaseAPIListView(ProjectBaseAPIListView):
    serializer_class = serializers.ProjectSubSerializer
    
    def get_queryset(self):
        base_qs = self.get_base_queryset()
        
        return base_qs.prefetch_related(
            "content_object__project"
        )
        

class ProjectSubDraftBaseAPIListView(ProjectSubBaseAPIListView):
    def get_base_queryset(self):
        return (
            super().get_base_queryset()
            .filter(
                object_id__in=self.model.objects.filter(is_draft=False).values_list('id', flat=True)
            )
        )

class UserRegistryAuditListView(BaseAPIListView):
    model = get_user_model()
    serializer_class = serializers.UserAuditSerializer

    def get_queryset(self):
        base_qs = super().get_queryset()
        return base_qs

    def get_permissions(self):
        return [HasDjangoPermission(["user.can_manage_users"])]

    
class ProjectInfoAuditListView(ProjectBaseAPIListView):
    model = p_models.Project
    serializer_class = serializers.ProjectInfoSerializer

class ProjectPlanAuditListView(ProjectSubDraftBaseAPIListView):
    model = p_models.Plan
    
class ProjectInitiationDataAuditListView(ProjectSubDraftBaseAPIListView):
    model = p_models.InitiationData

class ProjectBeforeImplementAuditListView(ProjectSubBaseAPIListView):
    model = p_models.BeforeImplement

class ProjectImplementAuditListView(ProjectSubBaseAPIListView):
    model = p_models.Implement

class ProjectFinishAuditListView(ProjectSubBaseAPIListView):
    model = p_models.Finish

class FileAccessAuditListview(BaseAPIListView):
    model = File
    serializer_class = serializers.FileAuditSerializer

    def get_permissions(self):
        return [HasDjangoPermission(["user.can_manage_resources"])]

    
    def get_queryset(self):
        base_qs = self.get_base_queryset()

        # TODO test 
        return base_qs.prefetch_related(
            "tags",
            "content_object__owner"
        ).annotate(
            requester_username=Subquery(
                AMTag.objects.filter(
                    audit_managements=OuterRef('pk'),
                    name__startswith='user-'
                ).annotate(
                    username=Subquery(
                        get_user_model().objects.filter(
                            id=Cast(
                                Substr(OuterRef('name'), 6),
                                output_field=IntegerField()
                            )
                        ).values('username')[:1]
                    )
                ).values('username')[:1]
            )
        )

    
class AuditManagementChangeAPIView(APIView):
    # TODO use `get_permissions` function
    def post(self, request, format=None):
        user = request.user
        data = request.data
        if not isinstance(data, list) or len(data) == 0:
            return Response({"error": "Data must be a non-empty list"}, status=400)

        content_type_id = data[0].get("content_type")
        model_class = ContentType.objects.get(id=content_type_id).model_class()
        if model_class == get_user_model():
            if not user.has_perm("user.can_manage_users"):
                return Response({"error": "Permission Error!"}, status=400)
        elif model_class.__name__ not in set(p_models.MODEL_AUDIT_PROGRESS_MAP.keys()):
            if not user.has_perm("user.can_manage_resources"):
                return Response({"error": "Permission Error!"}, status=400)
        
        # Collect all IDs from the input data
        ids = [item.get('id') for item in data if isinstance(item, dict) and 'id' in item]
        if not all(ids):
            return Response({"error": "Each item must have an id"}, status=400)
        
        # Fetch all existing instances at once
        instances = list(AuditManagement.objects.filter(id__in=ids))
        if len(instances) != len(ids):
            return Response({"error": "Some instances not found"}, status=400)

        data = list(map(lambda d: {**d, 'auditor': user.id}, data))
        
        serializer = serializers.AuditManagementSerializer(
            instances,
            data=data,
            many=True,
            partial=True
        )
        
        if serializer.is_valid():
            serializer.save()
            return Response({"message": "Objects updated successfully"})
        return Response({"error": serializer.errors}, status=400)
    
